/**
 * @author : 乔磊磊
 * @date   : 2025/5/20 15:30
 * @Desc   : tween扩展，添加bezierTo和jumpTo，方便使用
 */
import {ITweenOption, Node, Tween, tween, v3, Vec3} from "cc";

function bezier2(t: number, c1: number, c2: number, c3: number) {
    let t1 = 1 - t;
    return t1 * t1 * c1 + 2 * t * t1 * c2 + t * t * c3;
}

function bezier3(C1: number, C2: number, C3: number, C4: number, t: number) {
    let t1 = 1 - t;
    return t1 * (t1 * (C1 + (C2 * 3 - C1) * t) + C3 * 3 * t * t) + C4 * t * t * t;
}

function quadraticCurveTo(target: Node, duration: number, start: Vec3, cp: Vec3, to: Vec3): Tween<Node> {
    let opts: ITweenOption = Object.create(null);
    //@ts-ignore
    opts.onUpdate = (target: Node, ratio: number) => {
        let x = bezier2(ratio, start.x, cp.x, to.x);
        let y = bezier2(ratio, start.y, cp.y, to.y);
        let z = bezier2(ratio, start.z, cp.z, to.z);
        target.position = v3(x, y, z);
    }; 
    return tween(target).to(duration, {}, opts);
}

function bezierCurveTo(target: Node, duration: number, start: Vec3, c1: Vec3, c2: Vec3, to: Vec3): Tween<Node> {
    let opts: ITweenOption = Object.create(null);
    //@ts-ignore
    opts.onUpdate = (target: Node, ratio: number) => {
        let x = bezier3(start.x, c1.x, c2.x, to.x, ratio);
        let y = bezier3(start.y, c1.y, c2.y, to.y, ratio);
        let z = bezier3(start.z, c1.z, c2.z, to.z, ratio);
        target.position = v3(x, y, z);
    };
    return tween(target).to(duration, {}, opts);
}

/**
 * @description: bezierTo 缓动, 支持2阶和3阶贝塞尔曲线
 * @param target
 * @param duration
 * @param p1 起点
 * @param p2 控制点1
 * @param p3 控制点2/终点
 * @param p4 终点
 */
export function bezierTo(target: Node, duration: number, p1: Vec3, p2: Vec3, p3: Vec3, p4?: Vec3): Tween<Node> {
    if (p4) {
        return bezierCurveTo(target, duration, p1, p2, p3, p4);
    } else {
        return quadraticCurveTo(target, duration, p1, p2, p3);
    }
}

/**
 * @description: jumpTo 缓动，支持跳跃
 * @param target
 * @param duration
 * @param to 目标点
 * @param height 跳跃高度
 * @param jumps 跳跃次数
 */
export function jumpTo(target: Node, duration: number, to: Vec3, height: number, jumps: number = 1) {
    let start = target.position.clone();
    let delta = v3(to.x - start.x, to.y - start.y, to.z - start.z);

    let opts: ITweenOption = Object.create(null);
    //@ts-ignore
    opts.onUpdate = (target: Node, ratio: number) => {
        let frac = ratio * jumps % 1.0;
        let y = height * 4 * frac * (1 - frac);
        y += delta.y * ratio;

        let x = delta.x * ratio;
        let z = delta.z * ratio;
        target.position = v3(start.x + x, start.y + y, start.z + z);
    };
    return tween(target).to(duration, {}, opts);
}
